#-*- coding: utf-8 -*-

# (BSD 2-clause)
# Copyright (c) 2011, Mario Hock, Michael Tänzer, Karin Schmidt.
# All rights reserved.
# 
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 
# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation
# are those of the authors and should not be interpreted as representing
# official policies, either expressed or implied, of the copyright holders.


from gtk.gdk import pixbuf_new_from_file
import gtk
from os import path
import omnibus_steeringwheel as steeringwheel

from .user import User, DummyUser

class UserList(object):
    '''
    Takes care of the users list
    '''
    
    # Column names
    IMAGE_COLUMN = 0
    NAME_COLUMN = 1
    STATUS_COLUMN = 2
    OBJECT_COLUMN = 3
    
    
    def __init__(self, builder, connection):
        dir = path.dirname(__file__)
        self._pixbuf_connected = pixbuf_new_from_file(
                path.join(dir, "pics/connected.png"))
        self._pixbuf_pending = pixbuf_new_from_file(
                path.join(dir, "pics/pending.png"))
        self._pixbuf_disconnected = pixbuf_new_from_file(
                path.join(dir, "pics/disconnected.png"))
        self._pixbuf_error = pixbuf_new_from_file(
                path.join(dir, "pics/error.png"))
        
        self._builder = builder
        self._connection = connection
        
        # Register handlers
        def user_list_handler(connection, _, users, **__):
            self.update(users)
            connection.stat() ## XXX wenn ein user update kommt, könnte sich auch was bei den transfers verändert haben.. aber mir gefällt das so nicht! -- vor allem weil keine stat anfrage nötig ist, das kann man auch intern klären..
        
        self._connection.register_event_handler(user_list_handler,
                steeringwheel.EVENT_TYPE.USER_LIST)
        
        def user_myshares_handler(_, __, receiver, shares, **___):
            self.get_user_by_name(receiver).my_shares_update(shares)
        
        self._connection.register_event_handler(user_myshares_handler,
                steeringwheel.EVENT_TYPE.USER_MYSHARES)
        
        def user_othershares_handler(_, __, sender, offers, **___):
            self.get_user_by_name(sender).others_shares_update(offers)
        
        self._connection.register_event_handler(user_othershares_handler,
                steeringwheel.EVENT_TYPE.USER_OTHERSHARES)
        
        
        self._tree = builder.get_object('users_tree')
        self._model = builder.get_object('users_model')
        
        self._model.set_sort_column_id(self.NAME_COLUMN, gtk.SORT_ASCENDING)
        
        self._tree.get_selection().set_mode(gtk.SELECTION_SINGLE)
        
        User.current_user = DummyUser(self._builder)
        User.current_user.selected()
        
    def get_current_user(self):
        model, selection = self._tree.get_selection().get_selected()
        if selection is None:
            return None
        
        return model.get_value(selection, self.OBJECT_COLUMN)
    
    def get_user_by_name(self, user_name):
        #TODO: make efficient, e.g. by using a dict
        iter = self._model.get_iter_first()
        while iter:
            user_object = self._model.get_value(iter, self.OBJECT_COLUMN)
            if user_object.get_name() == user_name:
                return user_object
            
            iter = self._model.iter_next(iter)
        else:
            # user not found
            return None
    
    def update(self, users):
        # ATTENTION this only works because we work on a ListStore, otherwise
        # Iterators may become invalid when removing a user
        iter = self._model.get_iter_first()
        while iter:
            user_object = self._model.get_value(iter, self.OBJECT_COLUMN)
            user_name = user_object.get_name()
            
            for user in users:
                assert isinstance(user, steeringwheel.User)
                
                if user.name == user_name:
                    
                    status = user.connected
                    pixbuf = self._pixbuf_for_status(status)
                    
                    user_object.set_status(status)
                    self._model.set_value(iter, self.STATUS_COLUMN, status)
                    self._model.set_value(iter, self.IMAGE_COLUMN, pixbuf)
                    
                    # iterator is advanced here rather than in the while loop
                    # because the case of a deleted user also advances the
                    # the iterator
                    iter = self._model.iter_next(iter)
                    
                    # remove the user from the tree so we later have all users
                    # that are not in the list -> new users
                    users.remove(user)
                    break
            else:
                # The user is not in the list anymore
                user_object.remove()
                self._model.remove(iter)
                if not self.get_current_user():
                    # selected user was removed
                    User.current_user.deselected()
                    User.current_user = DummyUser(self._builder)
                    User.current_user.selected()
                
        for user in users:
            assert isinstance(user, steeringwheel.User)
            
            user_object = User(user.name,
                               user.connected,
                               self._builder,
                               self._connection)
            
            pixbuf = self._pixbuf_for_status(user.connected)
            # TODO: get rid of double bookkeeping possibly by writing custom
            # cell renderers. -> users_model becomes a liststore only containing
            # user objects, names and status icons are generated dynamically
            self._model.append( (pixbuf, user.name, user.connected, user_object) )
    
    def selection_updated(self):
        user = self.get_current_user()
        User.current_user.deselected()
        if not user:
            # no user selected
            User.current_user = DummyUser(self._builder)
        else:
            User.current_user = user
        
        User.current_user.selected()
    
    def _pixbuf_for_status(self, status):
        if status == steeringwheel.User.USERSTATUS.DISCONNECTED:
            return self._pixbuf_disconnected
        
        elif status == steeringwheel.User.USERSTATUS.CONNECTED:
            return self._pixbuf_connected
        
        elif status in steeringwheel.User.USERSTATUS.TRANSITIONS:
            return self._pixbuf_pending
            
        elif status in steeringwheel.User.USERSTATUS.ERRORS:
            return self._pixbuf_error
        
        else:
            raise steeringwheel.User.USERSTATUS.UnknownConnectionStatusError()
